package controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;

import com.jme3.input.InputManager;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control;

import controls.GameControl;

import old.BaseEventTrap;

import utilities.IDGenerator;
import utilities.Key;
import view.EViewList;
import view.AbstractView;
import view.IView;

import model.IModel;
import model.IPhysicalDataModel;
import model.AbstractModel;

import eventManager.AppEvent;
import eventManager.EventManager;
import eventManager.EventPortal;
import eventManager.IEventData;
import eventManager.IEventListener;

public abstract class AbstractController implements IController {
	
	protected Key key;
	protected HashMap<String, Spatial> spatials = new HashMap<String, Spatial>();
//	protected Node baseNode;	
	public HashMap<String, GameControl> gameControls = new HashMap<String, GameControl>();
//	public ArrayList<GameControl> controlList = new ArrayList<GameControl>();
	
	//Contain all events the controller listens for, mapped by destination
	protected HashMap<String, IEventListener> eventMap = new HashMap<String, IEventListener>();
	
	public AbstractController(ArrayList<Spatial> views) {
		//assign unique ID to object
		IDGenerator id = IDGenerator.getInstance();
		this.key = id.newID();
		
		for (Spatial spatial: views) {
			addSpatial(spatial);
		}		
	}
	
	public Key getKey() {
		return this.key;
	}
	
	public int getKeyValue() {
		return key.getValue();
	}
	
	public void addSpatial(Spatial spatial) {
		this.spatials.put(spatial.getName(), spatial);
	}
	
	public void removeSpatial(String name) {
		this.spatials.remove(name);
	}
	
//	public void setSpatial(Spatial spatial) {
//		this.spatial = spatial;
//		//registerGameControls();
//	}	
	
	public void registerEvents() {
		EventPortal.addListener(this, eventMap.keySet());
	}
	
	public void deleteEvents() {
		EventPortal.delListener(this, eventMap.keySet());				
	}
	
	//Loads events the controller listens for, strategies they use to handle them
	public void loadStrategy(IEventListener strategy) {
		Set<String> eventTypes = strategy.getEventTypes();
		
		for (String event: eventTypes) {
			eventMap.put(event, strategy);
			EventPortal.addListener(this, event);
		}
	}
	
	//QQQ: Deprecated.  Use EventPortal static methods
	//Handles all events generated in this MVC grouping and sent to the outside world
//	public void processOutgoingEvent(IEventData event) {
//		AppEvent baseEvent = (AppEvent) event;
//		//eventManager.queueEvent(baseEvent);
//		EventPortal.queueEvent(baseEvent);
//	}
	
	//Handles incoming events
	public void handleEvent(AppEvent event) {		
		if (eventMap.containsKey(event.getEventName())) {
			eventMap.get(event.getEventName()).handleEvent(event);
		}
	}
	
	public void addGameControl(GameControl control, String spatialName) {
//		this.controlList.add(control);
		Spatial test = spatials.get(spatialName);
		if (test!=null) {
			this.gameControls.put(control.getName(), control);
			control.setSpatial(test);
		}
		else {
			//Log that target spatial does not exist
		}
	}
	
	public void removeGameControl(String name) {
//		this.controlList.remove(gameControls.get(name));
		this.gameControls.remove(name);		
		//this.spatial.removeControl(clazz);
	}
	
	public abstract void loadSpecificEventStrategies();
	
	public Set<String> getEventTypes() {
		return eventMap.keySet();
	}
	
	public void update(float tpf) {
		for (GameControl control: gameControls.values()) {
			control.update(tpf);
		}		
	}
}